苹果手机 h5网页或公众号视频无法播放问题处理

您所在的位置:网站首页 ios 微信公众号播放视频 苹果手机 h5网页或公众号视频无法播放问题处理

苹果手机 h5网页或公众号视频无法播放问题处理

2024-07-13 14:30| 来源: 网络整理| 查看: 265

最近遇到奇葩问题,苹果手机公众号和h5网页中视频无法播放,在网络中找寻了好多解决方案,但还是没能彻底解决。

出现这个问题网上反馈多数因为两个情况,一、视频输出流问题;二、视频格式问题;围绕这两个点展开处理。

首先解决视频流输出问题,本次项目采用的java,springboot方式,项目默认结构为文件存储服务器本地,通过转换读取方式,直接访问文件地址即可获取。之后再网上找寻了很多输出视频流方式的例子;

这里将我们使用的例子代码贴出,仅供参考,具体可根据项目需求调整;其核心的断点流传输工具类可不同改动。

fileUpload.path: D:/fileUpload/ fileServic.path: http://192.168.2.198:8069/filestatic/ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; @Slf4j @RestController public class CommonController { /** * 请求访问域名地址 */ @Value("${fileServic.path}") private String fileServicPath; /** * 文件存储物理路径 */ @Value("${fileUpload.path}") private String fileUploadPath; /** * 获取视频 * * @param request * @param response */ @GetMapping("/filestatic/{date}/{fileName}") public void getPlayResource(HttpServletRequest request, HttpServletResponse response, @PathVariable(name = "date") String date, @PathVariable(name = "fileName") String fileName) { String rangeString = request.getHeader(HttpHeaders.RANGE); log.info("RANGE================,{}", rangeString); fileName = fileUploadPath + "/" + date + "/" + fileName; if (StringUtils.isNotEmpty(fileName)) { if (fileName.indexOf("mp4") > -1) { play(fileName,request,response); } else { try { writeBytes(fileName, response.getOutputStream()); } catch (IOException e) { log.error("下载文件失败", e); } } } } /** * 非视频类文件预览加载 * * @param filePath * @param os * @throws IOException */ public void writeBytes(String filePath, OutputStream os) throws IOException { FileInputStream fis = null; try { File file = new File(filePath); if (!file.exists()) { throw new FileNotFoundException(filePath); } fis = new FileInputStream(file); byte[] b = new byte[1024]; int length; while ((length = fis.read(b)) > 0) { os.write(b, 0, length); } } catch (IOException e) { throw e; } finally { if (os != null) { try { os.close(); } catch (IOException e1) { e1.printStackTrace(); } } if (fis != null) { try { fis.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } /** * 下载视频文件 path为本地文件路劲 * * @param path * @param request * @param response */ public void play(String path, HttpServletRequest request, HttpServletResponse response) { RandomAccessFile targetFile = null; OutputStream outputStream = null; try { outputStream = response.getOutputStream(); response.reset(); //获取请求头中Range的值 String rangeString = request.getHeader(HttpHeaders.RANGE); //打开文件 File file = new File(path); if (file.exists()) { //使用RandomAccessFile读取文件 targetFile = new RandomAccessFile(file, "r"); long fileLength = targetFile.length(); long requestSize = (int) fileLength; //分段下载视频 if (StringUtils.isNotEmpty(rangeString)) { //从Range中提取需要获取数据的开始和结束位置 long requestStart = 0, requestEnd = 0; String[] ranges = rangeString.split("="); if (ranges.length > 1) { String[] rangeDatas = ranges[1].split("-"); requestStart = Integer.parseInt(rangeDatas[0]); if (rangeDatas.length > 1) { requestEnd = Integer.parseInt(rangeDatas[1]); } } if (requestEnd != 0 && requestEnd > requestStart) { requestSize = requestEnd - requestStart + 1; } //根据协议设置请求头 response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes"); response.setHeader(HttpHeaders.CONTENT_TYPE, "video/mp4"); long length; if (requestEnd > 0) { length = requestEnd - requestStart + 1; response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length); response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + requestEnd + "/" + fileLength); } else { length = fileLength - requestStart; response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length); response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + (fileLength - 1) + "/" + fileLength); } // } boolean scPartialContent = true; //断点传输下载视频返回206 //如果是第一次请求,不返回206 if (ranges.length > 1) { String[] rangeDatas = ranges[1].split("-"); requestStart = Integer.parseInt(rangeDatas[0]); if (rangeDatas.length > 1 && requestStart == 0 && Integer.parseInt(rangeDatas[1]) == 1) { // requestEnd = Integer.parseInt(rangeDatas[1]); scPartialContent = false; log.info("第一次请求rangeString,{}", rangeString); } } if (scPartialContent) { log.info("不是第一次请求rangeString,{}", rangeString); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); } //设置targetFile,从自定义位置开始读取数据 targetFile.seek(requestStart); } else { //如果Range为空则下载整个视频 response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=test.mp4"); //设置文件长度 response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileLength)); } //从磁盘读取数据流返回 byte[] cache = new byte[4096]; try { while (requestSize > 0) { int len = targetFile.read(cache); if (requestSize < cache.length) { outputStream.write(cache, 0, (int) requestSize); } else { outputStream.write(cache, 0, len); if (len < cache.length) { break; } } requestSize -= cache.length; } } catch (IOException e) { // tomcat原话。写操作IO异常几乎总是由于客户端主动关闭连接导致,所以直接吃掉异常打日志 //比如使用video播放视频时经常会发送Range为0- 的范围只是为了获取视频大小,之后就中断连接了 log.info(e.getMessage()); } } else { // throw new RuntimeException("文件路劲有误"); } outputStream.flush(); } catch (Exception e) { log.error("文件传输错误", e); // throw new RuntimeException("文件传输错误"); } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { log.error("流释放错误", e); } } if (targetFile != null) { try { targetFile.close(); } catch (IOException e) { log.error("文件流释放错误", e); } } } } }

视频格式问题,参考地址https://zhuanlan.zhihu.com/p/532430872

我们的对比发下,上传的视频帧速率为25帧/秒无法播放,帧速率为30帧/秒可以正常。这和上述链接中讲解的苹果对视频帧数支持和格式说明有关系。

于是我们使用格式工厂(视频处理工具,免费的),进行转换后上传,真的可以正常播放了。到此问题全部解决。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3